package OS.experiment3;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Scanner;

public class FirstAdapt {

    //空闲分区表
    private List<NoUse> noUseList;

    //分区使用表
    private List<Used> usedList;

    //默认总内存
    private long MAX_SPACE = 1000000;

    FirstAdapt() {
        this.noUseList = new ArrayList<>();
        this.usedList = new ArrayList<>();

        this.noUseList.add(new NoUse(0, MAX_SPACE, 1));
    }

    public void menu() {
        Scanner scanner = new Scanner(System.in);
        int choice = -1;
        while (0 != choice) {
            System.out.println("-----功能菜单-----");
            System.out.println("0.退出");
            System.out.println("1.分配");
            System.out.println("2.回收");
            System.out.println("3.显示");
            System.out.println("请选择您需要得功能：");
            choice = scanner.nextInt();

            switch (choice) {
                case 1:
                    allocation();
                    break;
                case 2:
                    recycle();
                    break;
                case 3:
                    show();
                    break;
            }
        }
    }

    /**
     * 分配内存
     */
    private void allocation() {
         Scanner scanner = new Scanner(System.in);
         String workName;
         long length;

        System.out.println("请输入作业名称：");
        workName = scanner.next();
        if (null != findIt(workName)) {
            System.out.println("该作业已经分配了内存！");
        } else {
            System.out.println("请输入作业长度：");
            length = scanner.nextLong();

            //首次适应分配内存
            //是否已经成功分配了内存
            boolean success = false;
            for (NoUse noUse : noUseList) {
                if (noUse.getLength() >= length) {
                    //未分配减少
                    noUse.setStartAddress(noUse.getStartAddress() + length);
                    noUse.setLength(noUse.getLength() - length);

                    Used used = new Used(workName, noUse.getStartAddress() - length, length, 0);
                    usedList.add(used);
                    success = true;
                    break;
                }
            }

            if (success) {
                System.out.println("成功分配内存");
            } else {
                System.out.println("分配内存失败");
            }
        }
    }

    /**
     * 回收内存
     */
    private void recycle() {
        Scanner scanner = new Scanner(System.in);
        String workName;

        System.out.println("请输入要回收的作业名称：");
        workName = scanner.next();

        Used used = findIt(workName);
        usedList.remove(used);
        if (null != used) {
            //合并分区
            //在该已经分配分区前是否有可以合并的分区
            for (NoUse noUse : noUseList) {
                if (noUse.getStartAddress() < used.getStartAddress() && noUse.getStartAddress() + noUse.getLength() >= used.getStartAddress()) {
                    used.setStartAddress(noUse.getStartAddress());
                    used.setLength(noUse.getLength() + used.getLength());
                    noUseList.remove(noUse);
                    break;
                }
            }

            //在该已经分配分区后是否有可以合并的分区
            for (NoUse noUse : noUseList) {
                if (used.getStartAddress() + used.getLength() >= noUse.getStartAddress()) {
                    used.setLength(used.getLength() + noUse.getLength());
                    noUseList.remove(noUse);
                    break;
                }
            }

            noUseList.add(new NoUse(used.getStartAddress(), used.getLength(), 1));
            //对其按照内存起始地址排序
            Collections.sort(noUseList);
            System.out.println("回收内存成功！");
        } else {
            System.out.println("该作业没有分配内存！");
        }
    }

    /**
     * 显示内存
     */
    private void show() {
        System.out.println("-----空闲分区表-----");
        for (NoUse noUse : noUseList) {
            System.out.println(noUse + "\n");
        }
        System.out.println("-----分区使用表-----");
        for (Used used : usedList) {
            System.out.println(used + "\n");
        }
    }

    /**
     * 根据作业名在已经分配的作业中找同名作业
     */
    private Used findIt(String workName) {
        for (Used used : usedList) {
            if (workName.equals(used.getWordName())) return used;
        }
        return null;
    }

    public static void main(String[] args) {
        FirstAdapt firstAdapt = new FirstAdapt();
        firstAdapt.menu();
    }
}

/**
 * 空闲分区类
 */
class NoUse implements Comparable<NoUse>{
    //始址
    private long startAddress;

    //长度
    private long length;

    //状态，1表示空闲，0表示使用
    private int type;

    public NoUse(long startAddress, long length, int type) {
        this.startAddress = startAddress;
        this.length = length;
        this.type = type;
    }

    public long getStartAddress() {
        return startAddress;
    }

    public void setStartAddress(long startAddress) {
        this.startAddress = startAddress;
    }

    public long getLength() {
        return length;
    }

    public void setLength(long length) {
        this.length = length;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return "NoUse{" +
                "startAddress=" + startAddress +
                ", length=" + length +
                ", type=" + type +
                '}';
    }

    @Override
    public int compareTo(NoUse o) {
        return Math.toIntExact(getStartAddress() - o.getStartAddress());
    }
}

class Used {
    //作业名
    private String wordName;

    //始址
    private long startAddress;

    //长度
    private long length;

    //状态
    private int type;

    public Used(String wordName, long startAddress, long length, int type) {
        this.wordName = wordName;
        this.startAddress = startAddress;
        this.length = length;
        this.type = type;
    }

    public String getWordName() {
        return wordName;
    }

    public void setWordName(String wordName) {
        this.wordName = wordName;
    }

    public long getStartAddress() {
        return startAddress;
    }

    public void setStartAddress(long startAddress) {
        this.startAddress = startAddress;
    }

    public long getLength() {
        return length;
    }

    public void setLength(long length) {
        this.length = length;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    @Override
    public String toString() {
        return "Used{" +
                "wordName='" + wordName + '\'' +
                ", startAddress=" + startAddress +
                ", length=" + length +
                ", type=" + type +
                '}';
    }
}